package com.ruiyi.adrobot.mongo.fun.impl;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.ruiyi.adrobot.beans.AccountInfo;
import com.ruiyi.adrobot.beans.Device;
import com.ruiyi.adrobot.beans.Fun;
import com.ruiyi.adrobot.beans.common.MongoPageRequest;
import com.ruiyi.adrobot.mongo.fun.FunOperations;
import com.ruiyi.adrobot.utils.LoggerUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.*;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.query.Criteria.where;

/**
 * @author
 * @create 2017-06-08 9:46
 **/
public class FunRepositoryImpl implements FunOperations {
    @Autowired
    private MongoOperations mongo;

    @Override
    public Page<Fun> getListByPage(MongoPageRequest<Fun> mongoPageRequest) {
        Query query = new Query();
        List<Sort.Order> orders = new ArrayList<Sort.Order>();
        orders.add(new Sort.Order(Sort.Direction.DESC, "createDate"));
        Sort sort = new Sort(orders);
        mongoPageRequest.setSort(sort);
        Long count = mongo.count(query, Fun.class);
        List<Fun> funs = mongo.find(query.with(mongoPageRequest), Fun.class);
        return new PageImpl<Fun>(funs, mongoPageRequest, count);
    }

    @Override
    public void appendFlow(Integer fun, Fun.Flow flow) {
        Query query = new Query(Criteria.where("fun").is(fun));
        Update update = new Update();
        update.push("flows", flow);
        mongo.updateFirst(query, update, Fun.class);
    }

    @Override
    public void updateAction(Integer fun, String flowId, Fun.Flow.Action action) {
        Query query = new Query(Criteria.where("fun").is(fun).and("flows.id").is(flowId));
        Update update = new Update();
        update.set("flows.$.action", action);
        mongo.findAndModify(query, update, Fun.class);
    }

    @Override
    public Fun.Flow.Action findActionByFunAndFlowsId(Integer fun, String flowId) {
        Query query = new Query(where("fun").is(fun));
        query.fields().elemMatch("flows", where("id").is(flowId));
        return mongo.findOne(query, Fun.class).getFlows().get(0).getAction();
    }

    @Override
    public void removeUsedFunsByFun(Integer fun) {
        Query query = new Query();
        Update update = new Update();
        update.pull("usedFuns", fun);
        mongo.updateMulti(query, update, Device.class);
        Set<String> collectionNames = mongo.getCollectionNames();
        for (String collectionName : collectionNames) {
            try {
                Integer.parseInt(collectionName);
                LoggerUtil.info("正在删除" + collectionName + "中数据");
                mongo.updateMulti(query, update, collectionName);
            } catch (Exception e) {
                continue;
            }
        }
        Query accountInfoQuery = new Query(Criteria.where("_id").is(fun));
        mongo.remove(accountInfoQuery, AccountInfo.class);
    }

    @Override
    public void removeFlowByIdAndFun(String id, Integer fun) {
        Query query = new Query(Criteria.where("fun").is(fun));
        Update update = new Update();
        update.pull("flows", new BasicDBObject("id", id));
        mongo.updateFirst(query, update, Fun.class);
    }

    @Override
    public Map<String, String> findFlowMap() {
        Map<String, String> flowMap = new LinkedHashMap<>();
        Aggregation agg = newAggregation(
                Aggregation.unwind("flows"),
                Aggregation.project("flows._id", "flows.describe")
        );
        AggregationResults<Fun.Flow> outputType = mongo.aggregate(agg, "fun", Fun.Flow.class);
        for (Fun.Flow flow : outputType.getMappedResults()) {
            flowMap.put(flow.getId(), flow.getDescribe());
        }
        return flowMap;
    }

    @Override
    public Map<Integer, String> findFunMap() {
        Map<Integer, String> funMap = new LinkedHashMap<>();
        List<Fun> funs = mongo.findAll(Fun.class);
        for (Fun fun : funs) {
            funMap.put(fun.getFun(), fun.getDescribe());
        }
        return funMap;
    }

    @Override
    public DBObject findFlowByFunAndFlowId(Integer fun, String flowId) {
        DBObject projectFields = new BasicDBObject();
        projectFields.put("ptimes", "$_id.ptimes");
        Aggregation agg = newAggregation(
                Aggregation.match(Criteria.where("fun").is(fun)),
                Aggregation.unwind("flows"),
                Aggregation.match(Criteria.where("flows._id").is(flowId)),
                Aggregation.project("fun").and("describe").as("funName").and("flows.describe").as("flowName")
        );
        AggregationResults<DBObject> outputType = mongo.aggregate(agg, "fun", DBObject.class);
        return outputType.getUniqueMappedResult();
    }

}
